package org.zjvis.datascience.service.gis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zjvis.datascience.common.dto.gis.GisLayersDTO;
import org.zjvis.datascience.common.dto.gis.GisTabsDTO;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.service.mapper.GisLayersMapper;

import java.util.List;
import java.util.stream.Collectors;
import org.zjvis.datascience.service.mapper.GisTabsMapper;

import static org.zjvis.datascience.common.gis.GisUtils.GisUtil.LAYERS_DEFAULT_NAME;

@Service
public class GisLayersService {

    @Autowired
    private GisLayersMapper gisLayersMapper;

    @Autowired
    private GisTabsMapper gisTabsMapper;

    public String queryTbNameByLayerId(Long layerId) {
        return gisLayersMapper.queryTbNameByLayerId(layerId);
    }

    public List<GisLayersDTO> queryLayersByTabId(Long tabId) {
        return gisLayersMapper.queryLayersByTabId(tabId);
    }

    public void deleteLayerByTabId(Long tabId) {
        gisLayersMapper.deleteLayerByTabId(tabId);
    }

    public void deleteLayerByLayerId(Long layerId) {
        gisLayersMapper.deleteLayerByLayerId(layerId);
    }

    public GisLayersDTO queryLayerInfoById(Long layerId) {
        return gisLayersMapper.queryLayerInfoById(layerId);
    }

    public boolean update(GisLayersDTO layer) {
        return gisLayersMapper.update(layer);
    }

    public String getLayerViewById(Long layerId) {
        String viewName = gisLayersMapper.getLayerViewById(layerId);
        return viewName;
    }

    public void deleteLayers(List<Long> layerIds) {
        for (Long layerId : layerIds) {
            deleteLayerByLayerId(layerId);
        }
    }

    public Long checkLayer(String tbName) {
        return gisLayersMapper.checkLayer(tbName);
    }

    public void updateLoadDataOrder(List<Long> orders) {
        for (Long order : orders) {
            GisLayersDTO layersDTO = queryLayerInfoById(order);
            int newOrder = orders.indexOf(order) + 1;
            layersDTO.setLayerOrder((long) newOrder);
            update(layersDTO);
        }
    }

    public void updateAnalysisOrder(List<Long> Ids, Long userId, Long tabId) {
        for (Long Id : Ids) {
            GisLayersDTO layersDTO = queryLayerInfoById(Id);
            Long updatedOrder = layersDTO.getLayerOrder() + 1;
            layersDTO.setLayerOrder(updatedOrder);
            update(layersDTO);
        }
    }

    public void updateLayerOrder(Long userId, Long tabId, List<Long> datasetIds) {
        //加载了几个图层，原图层就加几个order
        int len = datasetIds.size();
        List<Long> Ids = queryLayerIds(userId, tabId);
        for (Long Id : Ids) {
            GisLayersDTO layersDTO = queryLayerInfoById(Id);
            Long updatedOrder = layersDTO.getLayerOrder() + len;
            layersDTO.setLayerOrder(updatedOrder);
            update(layersDTO);
        }
    }


    public List<String> queryLayerNamesByTabId(Long tabId) {
        return gisLayersMapper.queryLayerNamesByTabId(tabId);
    }

    public Long getAddLayerOrder(Long userId, Long tabId) {
//        加载图层后放在最后一层
        Long maxOrder = gisLayersMapper.getMaxOrder(userId, tabId);
        if (maxOrder == null) {
            Long res = 1L;
            return res;
        }
        Long setOrder = maxOrder + 1;
        return setOrder;
    }

    /**
     * @param tabId
     * @param projectId
     * @param newName
     * @param tbName
     * @param type
     * @return filledLayerDTO
     */
    public GisLayersDTO setEmptyLayer(Long tabId, Long projectId, String newName, String tbName, String type) {
        GisLayersDTO emptyLayerDTO = new GisLayersDTO();
        emptyLayerDTO.setUserId(JwtUtil.getCurrentUserId());
        emptyLayerDTO.setTabId(tabId);
        emptyLayerDTO.setProjectId(projectId);
        emptyLayerDTO.setPipelineId(null);
        emptyLayerDTO.setTaskId(null);
        emptyLayerDTO.setDataJson(null);
        emptyLayerDTO.setLayerName(newName);
        emptyLayerDTO.setSourceTable(tbName);
        emptyLayerDTO.setVisible(1L);
        emptyLayerDTO.setType(type);
        return emptyLayerDTO;
    }


    /**
     * 添加加载数据图层（设置order为末尾）
     *
     * @param projectId
     * @param tabId
     * @param tbName
     * @param datasetName
     * @param type
     * @return LayerDTO
     */
    public GisLayersDTO addLoadLayer(Long projectId, Long userId, Long tabId, String tbName, String datasetName, String type) {
        List<String> names = queryLayerNamesByTabId(tabId);
        String setName = datasetName == null ? LAYERS_DEFAULT_NAME : datasetName;
        String newName = createTabsName(names, setName);
//        Long layerOrder = getAddLayerOrder(userId, tabId);
        GisLayersDTO LayerDTO = setEmptyLayer(tabId, projectId, newName, tbName, type);
        LayerDTO.setLayerOrder(1L);
        saveLayer(LayerDTO);
        return LayerDTO;
    }

    /**
     * 添加空间分析图层（设置order为1）
     *
     * @param projectId
     * @param tabId
     * @param tbName
     * @param datasetName
     * @param type
     * @return LayerDTO
     */
    public GisLayersDTO addAnalysisLayer(Long projectId, Long userId, Long tabId, String tbName, String datasetName, String type) {
        List<String> names = queryLayerNamesByTabId(tabId);
        String setName = datasetName == null ? LAYERS_DEFAULT_NAME : datasetName;
        String newName = createTabsName(names, setName);
        GisLayersDTO LayerDTO = setEmptyLayer(tabId, projectId, newName, tbName, type);
        LayerDTO.setLayerOrder(1L);
        saveLayer(LayerDTO);
        return LayerDTO;
    }


    public Long saveLayer(GisLayersDTO layer) {
        gisLayersMapper.save(layer);
        return layer.getId();
    }

    /**
     * 校验是否有重名，是则加序号
     *
     * @param names
     * @param name
     * @return checked name
     */
    public String createTabsName(List<String> names, String name) {
        String newName;
        if (names.size() == 0) {
            newName = name;
        } else {
            List<String> defaultName = names.stream()
                    .filter(n -> n.matches("^" + name + "(\\([0-9]+\\))?$"))
                    .collect(Collectors.toList());
            List<Integer> order = defaultName.stream()
                    .map(s -> s.equals(name) ? "0" : s.substring(name.length() + 1, s.length() - 1))
                    .map(Integer::parseInt)
                    .sorted()
                    .collect(Collectors.toList());
            if (order.size() == 0) {
                newName = name;
            } else {
                newName = String.format(name + "(%d)", order.get(order.size() - 1) + 1);
            }
        }
        return newName;
    }

    public List<Long> queryLayerIds(Long userId, Long tabId) {
        return gisLayersMapper.queryLayerIds(userId, tabId);
    }


    public GisLayersDTO addLoadLayersByTabId(Long projectId, Long userId, Long tabId, String tbName, String datasetName, String type) {
        return addLoadLayer(projectId, userId, tabId, tbName, datasetName, type);
    }

    public List<Long> queryOrdersByTabId(Long tabId) {
        return gisLayersMapper.queryOrdersByTabId(tabId);
    }

    public boolean copyLayers(Long tabId, Long copyTabId) {
        return gisLayersMapper.copyLayers(tabId, copyTabId);
    }

    public String getLayerNameById(Long layerId){
        return gisLayersMapper.queryLayerNameById(layerId);
    }

    public GisTabsDTO queryTabInfoById(Long tabId){
        return gisTabsMapper.queryTabInfoById(tabId);
    }

    public void saveInfo(Long tabId, JSONObject tabInfo, JSONArray layers,String tabName){
        GisTabsDTO tab = gisTabsMapper.queryTabInfoById(tabId);
        tab.setTabName(tabName);
        tab.setDataJson(tabInfo.toJSONString());
        gisTabsMapper.update(tab);

        for (Object obj: layers) {
            JSONObject layerJson = (JSONObject) JSONObject.toJSON(obj);
            Long layerId = layerJson.getLong("id");
            GisLayersDTO layer = gisLayersMapper.queryLayerInfoById(layerId);
            JSONObject tagInfo = layerJson.getJSONObject("data");
            layer.setVisible(layerJson.getLong("visible"));
            layer.setLayerName(layerJson.getString("name"));
            layer.setDataJson(tagInfo.toJSONString());
            gisLayersMapper.update(layer);
        }
    }

    public JSONObject queryMarker(Long layerId){
        return JSONObject.parseObject(gisLayersMapper.queryLayerInfoById(layerId).getDataJson()).getJSONObject("marker");
    }

}
